﻿using AutoMapper.Extensions.ExpressionMapping;
using BCCommon;
using BCCommon.OAEnums.WorkflowActive;
using BCDto.OA.WorkflowActive.WorkflowActivityOperation;
using BCService;
using BCService.OA.WorkflowTemplate.WorkflowTemplate;
using BCWorkflowEngine;
using Dapper;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using TMSWorkflowAutoJob.Redis;

namespace TMSWorkflowAutoJob
{
    class Program
    {
        public static IServiceCollection services { get; set; }
        public static IConfiguration configuration { get; set; }
        static void Main(string[] args)
        {
            var builder = new ConfigurationBuilder();
#if DEBUG
            Console.WriteLine("DEBUG");
            builder.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
#else
            Console.WriteLine("RELEASE");
            builder.AddJsonFile("/mnt/web/config/appsettings.production.json", optional: true, reloadOnChange: true);
#endif
            configuration = builder.Build();
            GeneralContainer.Configuration = configuration;
            services = new ServiceCollection()
                .AddLogging()
                .AddScoped<ILoggerFactory, LoggerFactory>()
                .AddMySql(option =>
                {
                    option.MasterConnectionString = configuration["MySqlConnectionString"];
                    option.SlaveConnectionString = configuration["MySqlConnectionString"];
                })
                .AddRedis(options =>
                {
                    if (bool.TryParse(configuration["EnableRedis"], out bool enableRedis))
                    {
                        options.EnableRedis = enableRedis;
                    }
                    options.RedisConnectionString = configuration["RedisConnectionString"];
                    options.RedisDatabaseNo = configuration["RedisDatabaseNo"];
                })
                .AddScoped<IApplicationContextService, ConsoleContextService>()
                .AddServices()
                .AddMapperConfiguration();

            #region 模型映射
            var mappingConfiguration = new AutoMapper.MapperConfiguration(cfg =>
            {
                cfg.AddMaps(Assembly.Load(new AssemblyName("BCService")));
                cfg.AddExpressionMapping();
            });
            mappingConfiguration.CompileMappings();
            BCService.Utils.MapperExtension.Mapper = mappingConfiguration.CreateMapper();

            var workflowConfiguration = new AutoMapper.MapperConfiguration(cfg =>
            {
                cfg.AddMaps(Assembly.Load(new AssemblyName("BCWorkflowEngine")));
                cfg.AddExpressionMapping();
            });
            workflowConfiguration.CompileMappings();

            BCWorkflowEngine.Utils.MapperExtension.Mapper = workflowConfiguration.CreateMapper();
            #endregion

            services.AddSingleton(typeof(IConfiguration), configuration);
            Console.WriteLine("Service Count:" + services.Count);
            IServiceProvider serviceProvider = services.BuildServiceProvider(new ServiceProviderOptions().ValidateScopes);
            //ILoggerFactory loggerFactory = serviceProvider.GetService<ILoggerFactory>().AddConsole(LogLevel.Debug);
            //全局服务提供
            GeneralContainer.ServiceProvider = serviceProvider;
            TMSWorkflowStepConditionExecution(serviceProvider);
        }

        private static void TMSWorkflowStepConditionExecution(IServiceProvider serviceProvider)
        {
            Console.WriteLine("工作流步骤【条件】推进处理开始");
            IWorkflowEngine workflowEngine = serviceProvider.GetService<IWorkflowEngine>();
            IWorkflowTemplateService workflowTemplateService = serviceProvider.GetService<IWorkflowTemplateService>();

            Console.WriteLine("构建工作流步骤【条件】推进服务完成");
            try
            {
                Console.WriteLine("开始调用处理程序");
                var stepNodeList = workflowEngine.GetWorkflowStepConditionStatusActiveList();
                foreach (var item in stepNodeList)
                {
                    var conditionConfigs = workflowTemplateService.GetWorkflowTemplateStepConditionConfigs(item.TemplateCode);
                    var stepFormConfigs = workflowEngine.GetActivityStepFormConfigList(item.WorkflowActivityId);
                    int count = conditionConfigs.Count();
                    int correctCount = 0;
                    int incorrectCount = 0;
                    foreach (var condition in conditionConfigs)
                    {
                        var activeStepFormConfig = stepFormConfigs.FirstOrDefault(p => p.FormConfigCode == condition.FormConfigCode);
                        if (activeStepFormConfig != null)
                        {
                            if (activeStepFormConfig.IsSpecificForm)
                            {
                                if (activeStepFormConfig.SpecificFormItemActivity.Any(p => p.FormDatabase == condition.FormDatabase && p.FormTable == condition.FormTable && p.BoundField == condition.BoundField))
                                {
                                    var formItem = activeStepFormConfig.SpecificFormItemActivity.First(p => p.FormDatabase == condition.FormDatabase && p.FormTable == condition.FormTable && p.BoundField == condition.BoundField);
                                    if (compareValue(condition.CompareType, condition.CompareValue, formItem.ItemValue))
                                    {
                                        correctCount = correctCount + 1;
                                    }
                                    else
                                    {
                                        incorrectCount = incorrectCount + 1;
                                    }
                                }

                            }
                            else
                            {
                                if (activeStepFormConfig.FormItemActivity.Any(p => p.FormDatabase == condition.FormDatabase && p.FormTable == condition.FormTable && p.BoundField == condition.BoundField))
                                {
                                    var formItem = activeStepFormConfig.FormItemActivity.First(p => p.FormDatabase == condition.FormDatabase && p.FormTable == condition.FormTable && p.BoundField == condition.BoundField);
                                    if (compareValue(condition.CompareType, condition.CompareValue, formItem.ItemValue))
                                    {
                                        correctCount = correctCount + 1;
                                    }
                                    else
                                    {
                                        incorrectCount = incorrectCount + 1;
                                    }
                                }
                            }
                        }
                    }
                    if (incorrectCount > 0)
                    {
                        workflowEngine.Execution(new WorkflowActivityOperationRequestDto()
                        {
                            StepCompleteType = OAActivityStepCompleteType.Reject,
                            WorkflowActivityId = item.WorkflowActivityId,
                            WorkflowActivityStepId = item.WorkflowActivityStepId
                        });
                    }
                    else
                    {
                        workflowEngine.Execution(new WorkflowActivityOperationRequestDto()
                        {
                            StepCompleteType = OAActivityStepCompleteType.Pass,
                            WorkflowActivityId = item.WorkflowActivityId,
                            WorkflowActivityStepId = item.WorkflowActivityStepId
                        });
                    }
                }
                Console.WriteLine("完成");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Log(JsonConvert.SerializeObject(ex));
            }
        }

        private static bool compareValue(string compareType, string compareValue, string sourceValue)
        {
            switch (compareType)
            {
                case "NotEquals":
                    return !compareValue.Equals(sourceValue);
                case "GreaterThan":
                    {
                        if (!int.TryParse(compareValue, out int a))
                        {
                            throw new ArgumentException("对比值应为数字!");
                        }
                        if (!int.TryParse(sourceValue, out int b))
                        {
                            throw new ArgumentException("对比来源值应为数字!");
                        }
                        return b > a;
                    }
                case "Than":
                    {
                        if (!int.TryParse(compareValue, out int a))
                        {
                            throw new ArgumentException("对比值应为数字!");
                        }
                        if (!int.TryParse(sourceValue, out int b))
                        {
                            throw new ArgumentException("对比来源值应为数字!");
                        }
                        return b < a;
                    }
                case "ThanEquals":
                    {
                        if (!int.TryParse(compareValue, out int a))
                        {
                            throw new ArgumentException("对比值应为数字!");
                        }
                        if (!int.TryParse(sourceValue, out int b))
                        {
                            throw new ArgumentException("对比来源值应为数字!");
                        }
                        return b <= a;
                    }
                case "GreaterThanEquals":
                    {
                        if (!int.TryParse(compareValue, out int a))
                        {
                            throw new ArgumentException("对比值应为数字!");
                        }
                        if (!int.TryParse(sourceValue, out int b))
                        {
                            throw new ArgumentException("对比来源值应为数字!");
                        }
                        return b >= a;
                    }
                case "In":
                    {
                        return sourceValue.IndexOf(compareValue) > -1;
                    }
                case "NotIn":
                    {
                        return sourceValue.IndexOf(compareValue) == -1;
                    }
                case "NotNULL":
                    {
                        return !string.IsNullOrWhiteSpace(sourceValue);
                    }
                case "IsNULL":
                    {
                        return string.IsNullOrWhiteSpace(sourceValue);
                    }
                case "Between":
                    {
                        string[] betweenVlaues = compareValue.Split("~");
                        if (betweenVlaues.Length != 2)
                        {
                            throw new ArgumentException("介于表达式不正确!");
                        }
                        if (!int.TryParse(betweenVlaues[0], out int a))
                        {
                            throw new ArgumentException("介于：开始对比值应为数字!");
                        }
                        if (!int.TryParse(betweenVlaues[1], out int b))
                        {
                            throw new ArgumentException("介于：结束对比值应为数字!");
                        }
                        if (!int.TryParse(sourceValue, out int c))
                        {
                            throw new ArgumentException("介于：对比来源值应为数字!");
                        }
                        return (a < c) && (c < b);
                    }
                case "NotBetween":
                    {
                        string[] betweenVlaues = compareValue.Split("~");
                        if (betweenVlaues.Length != 2)
                        {
                            throw new ArgumentException("不介于表达式不正确!");
                        }
                        if (!int.TryParse(betweenVlaues[0], out int a))
                        {
                            throw new ArgumentException("不介于：开始对比值应为数字!");
                        }
                        if (!int.TryParse(betweenVlaues[1], out int b))
                        {
                            throw new ArgumentException("不介于：结束对比值应为数字!");
                        }
                        if (!int.TryParse(sourceValue, out int c))
                        {
                            throw new ArgumentException("不介于：对比来源值应为数字!");
                        }
                        return (a > c) || (c > b);
                    }
                default:
                    return compareValue.Equals(sourceValue);
            }
        }

        private static void Log(string message)
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(Directory.GetCurrentDirectory());

            FileInfo fileInfo = new FileInfo(Path.Combine(directoryInfo.FullName, "TMSWorkflowConsoleError_Condition", DateTime.Now.ToString("yyyy-MM-dd") + ".txt").ToString());
            
            if (!Directory.Exists(Path.Combine(directoryInfo.FullName, "TMSWorkflowConsoleError_Condition")))
            {
                Directory.CreateDirectory(Path.Combine(directoryInfo.FullName, "TMSWorkflowConsoleError_Condition"));
            }
            
            try
            {
                if (!fileInfo.Exists)
                {
                    using (StreamWriter sw = fileInfo.CreateText())
                    {
                        sw.WriteLine("*****************************************");
                        sw.WriteLine("当前时间：{0}", DateTime.Now.ToString());

                        sw.WriteLine("{0}", message);

                        sw.WriteLine();
                    }
                }
                else
                {
                    using (StreamWriter sw = fileInfo.AppendText())
                    {
                        sw.WriteLine("*****************************************");
                        sw.WriteLine("当前时间：{0}", DateTime.Now.ToString());

                        sw.WriteLine("{0}", message);

                        sw.WriteLine();
                    }
                }
            }
            catch (Exception e)
            {
                using (StreamWriter sw = fileInfo.AppendText())
                {
                    sw.WriteLine("*****************************************");
                    sw.WriteLine("当前时间：{0}", DateTime.Now.ToString());
                    sw.WriteLine("构建失败:");
                    sw.WriteLine("{0}", message);

                }
            }
        }
    }
}
